using System;
using System.Collections.Generic;
using NBusiness.CodeDom;
using NBusiness.ESharp.Compiler;
using NBusiness.CodeDom.Compiler;
using NBusiness.Templates;
using System.Linq;
using NBusiness.CodeDom.Services;

namespace NBusiness.ESharp
{
    [Serializable]
    public class ESharpEntity : Entity
    {
        #region Find helpers
        internal IValidatable[] FindValidatable(string name)
        {

            IValidatable[] foundFields = this.Fields.FindAll(new Predicate<EntityField>(
                delegate(EntityField field)
                {
                    return field.Name == name;
                })).ToArray();

            IValidatable[] foundRelationship = this.Relationships.FindAll(new Predicate<EntityRelationship>(
                delegate(EntityRelationship relationship)
                {
                    return relationship.Name == name;
                })).ToArray();

            List<IValidatable> found = new List<IValidatable>();
            found.AddRange(foundFields);
            found.AddRange(foundRelationship);

            return found.ToArray();
        }
        #endregion

        #region Attach
        protected override void Attach()
        {
            foreach (EntityRelationship relationship in Relationships)
            {
                if(relationship.From == this)
                    (relationship as ICompileUnit).Attach();
            }

            foreach (EntityRule rule in Rules)
                (rule as ICompileUnit).Attach();

            List<EntityUsing> @using = new List<EntityUsing>();
            if ((Parent as EntityFamily).Root.Using.ContainsKey(Elements[0].Path ?? ""))
                @using.AddRange((Parent as EntityFamily).Root.Using[Elements[0].Path ?? ""]);

            Using.AddRange(@using);

            this.FindTemplates(@using.ToArray(), Provider, OnBuildError);
        }
       
        #endregion

        #region Initialize Assignment logic
        protected override void InitializeAssignmentLogic()
        {
            //Entity
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.EntityName,
                new AssignmentLogicHandler(AssignEntityName)));

            Assignments.Add(new AssignmentLogic(ESharpEntityElementTypes.GroupBegin));

            //Entity template, will be attached to the template later.
            Assignments.Add(new AssignmentLogic(ESharpEntityElementTypes.EntityAs));

            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.EntityTemplateType,
                new AssignmentLogicHandler(CreateNewTemplate)));

            //Create "field"
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.FieldDeclaration,
                new AssignmentLogicHandler(CreateNewField)));

            //Create "access" rule
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.AccessDeclaration,
                new AssignmentLogicHandler(CreateAccessRule)));

            //Create "validation" rule
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.ValidateDeclaration,
                new AssignmentLogicHandler(CreateValidationRule)));

            //Create "authorize" rule
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.AuthorizeDeclaration,
                new AssignmentLogicHandler(CreateAuthorizeRule)));

            //Create "action" 
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.ActionDeclaration,
                new AssignmentLogicHandler(CreateAction)));

            //Create "relationship"
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.RelationshipDeclaration,
                new AssignmentLogicHandler(CreateRelationship)));

            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.GroupEnd,
                PostAssignmentAction.Stop));

            Assignments.Add(new AssignmentLogic(ESharpEntityElementTypes.WhiteSpace));
            Assignments.Add(new AssignmentLogic(ESharpEntityElementTypes.Comment));
        }
        #endregion

        #region Do Assignments
        private void AssignEntityName(object sender, AssignmentLogicEventArgs e)
        {
            Name = e.Elements.Peek().Value;
        }

        private void CreateNewTemplate(object sender, AssignmentLogicEventArgs e)
        {
            ESharpTemplate template = new ESharpTemplate();
            As.Add(template);
            template.Parent = this;
            template.Name = e.Elements.Peek().Value;
            (template as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.EntityTemplateType);
        }

        private void CreateNewField(object sender, AssignmentLogicEventArgs e)
        {
            ESharpField f = new ESharpField();
            Fields.Add(f);
            f.Parent = this;
            (f as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.FieldDeclaration);
        }

        private void CreateAccessRule(object sender, AssignmentLogicEventArgs e)
        {
            ESharpAccess rule = new ESharpAccess();
            rule.Parent = this;
            Rules.Add(rule);
            rule.Parent = this;
            (rule as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.AccessDeclaration);
        }
        private void CreateValidationRule(object sender, AssignmentLogicEventArgs e)
        {
            ESharpValidation rule = new ESharpValidation();
            rule.Parent = this;
            Rules.Add(rule);
            rule.Parent = this;
            (rule as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.ValidateDeclaration);
        }

        private void CreateAuthorizeRule(object sender, AssignmentLogicEventArgs e)
        {
            ESharpAuthorization rule = new ESharpAuthorization();
            rule.Parent = this;
            Rules.Add(rule);
            (rule as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.AuthorizeDeclaration);
        }

        private void CreateAction(object sender, AssignmentLogicEventArgs e)
        {
            ESharpAction a = new ESharpAction();
            Actions.Add(a);
            (a as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.ActionDeclaration);
        }

        private void CreateRelationship(object sender, AssignmentLogicEventArgs e)
        {
            ESharpRelationship a = new ESharpRelationship();
            a.Parent = this;
            (a as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.RelationshipDeclaration);
            Relationships.Add(a);
            a.From = this;
        }
        #endregion

    }
}
